// 定义观察者模式相关的 trait 和结构体

// 观察者 trait，定义了观察者的更新方法
trait Observer {
    fn update(&self, message: &str);
}

// 主题 trait，定义了主题的管理方法
trait Subject {
    fn attach(&mut self, observer: Box<dyn Observer>);
    fn detach(&mut self, observer: *const dyn Observer);
    fn notify(&self);
}

// 具体主题 ConcreteSubject
struct ConcreteSubject {
    observers: Vec<Box<dyn Observer>>, // 存储观察者的集合
    state: String,                     // 主题状态
}

impl ConcreteSubject {
    // 创建新的 ConcreteSubject 实例
    fn new() -> Self {
        Self {
            observers: Vec::new(),
            state: String::new(),
        }
    }

    // 设置主题状态，并通知所有观察者
    fn set_state(&mut self, state: &str) {
        self.state = state.to_string();
        self.notify();
    }
}

// 实现 Subject trait for ConcreteSubject
impl Subject for ConcreteSubject {
    // 添加观察者到集合中
    fn attach(&mut self, observer: Box<dyn Observer>) {
        self.observers.push(observer);
    }

    // 从集合中移除观察者
    fn detach(&mut self, observer: *const dyn Observer) {
        self.observers.retain(|obs| !std::ptr::eq(&**obs, observer));
    }

    // 通知所有观察者，调用其更新方法
    fn notify(&self) {
        for observer in &self.observers {
            observer.update(&self.state);
        }
    }
}

// 具体观察者 ConcreteObserver
struct ConcreteObserver {
    name: String,
}

impl ConcreteObserver {
    // 创建新的 ConcreteObserver 实例
    fn new(name: &str) -> Self {
        Self {
            name: name.to_string(),
        }
    }
}

// 实现 Observer trait for ConcreteObserver
impl Observer for ConcreteObserver {
    // 更新方法的具体实现，打印接收到的消息
    fn update(&self, message: &str) {
        println!("{} received message: {}", self.name, message);
    }
}

// 主函数入口
pub fn main() {
    let mut subject = ConcreteSubject::new(); // 创建 ConcreteSubject 实例

    // 创建两个具体的观察者实例
    let observer1 = Box::new(ConcreteObserver::new("Observer 1"));
    let observer2 = Box::new(ConcreteObserver::new("Observer 2"));

    let observer1_ptr = &*observer1 as *const dyn Observer; // 获取 observer1 的指针

    subject.attach(observer1); // 将观察者 observer1 添加到主题中
    subject.attach(observer2); // 将观察者 observer2 添加到主题中

    subject.set_state("State has changed"); // 设置主题状态并通知观察者

    // 分离观察者 observer1
    subject.detach(observer1_ptr);

    subject.set_state("State has changed again"); // 再次设置主题状态并通知观察者
}
